#pragma once
#include <iostream>
#include <chrono>
#include "utility/index.hpp"
#include "request_access/index.hpp"
#include "data_access/index.hpp"
#include "components/index.hpp"
#include "actions.hpp"

using namespace std;
using namespace utility;

namespace components2 {
    class MaterialProductCheck : public components::EntityRequest {
    public:
        COMPONENT_INSTANCE_FUNCTION(MaterialProductCheck);

        MaterialProductCheck();

        any UpdateStatus();

        any Insert2();

        any CancelReview();

    private:
        bool updateMaterialProductStockNum(const any &materialProductId, float lostNum);

        bool insertMaterialProductStockRecord(const any &materialProductId, const any &storageId, float lostNum, bool isCancel);
    };

    MaterialProductCheck::MaterialProductCheck() {
        SET_METHOD_ACTION(UpdateStatus);
        SET_METHOD_ACTION(CancelReview);
        SET_METHOD_ACTION(Insert2);
    }

    std::any MaterialProductCheck::UpdateStatus() {
        lock_guard<std::mutex> lock(mtx);

        EntityData dict = Request->RequestEntity.GetEntityData(Entity->Name);

        auto oldEntityData = SelectEntityByPrimaryKey(QueryRequest->PrimaryKeyValue);
        if (oldEntityData.Empty()) return Request->GetMessageMap("原料库存盘点不存在");

        auto msg = CompareVersion(dict, oldEntityData);
        if (!msg.empty()) return Request->GetMessageMap(msg);

        auto status = dict.GetInt("Status");
        auto oldStatus = oldEntityData.GetInt("Status");
        auto lostNum = oldEntityData.GetFloat("LostNum");
        auto materialProductId = oldEntityData.Get("MaterialProductId");

        bool blSucceed = true;
        try {
            DataBase->BeginTransaction();

            blSucceed = Actions::UpdateStatusAndReview(shared_from_this(), nullptr, dict, 8);

            if (blSucceed && lostNum != 0) {
                //审核通过,更新商品库存
                if (status == 2) {
                    blSucceed = insertMaterialProductStockRecord(materialProductId, QueryRequest->PrimaryKeyValue, lostNum, false);
                    if (blSucceed)blSucceed = updateMaterialProductStockNum(materialProductId, lostNum);
                } else if (status == 0 && oldStatus == 2) {
                    blSucceed = insertMaterialProductStockRecord(materialProductId, QueryRequest->PrimaryKeyValue, lostNum, true);
                    if (blSucceed) blSucceed = updateMaterialProductStockNum(materialProductId, 0 - lostNum);
                }
            }

            if (blSucceed) {
                DataBase->CommitTransaction();
            } else DataBase->RollbackTransaction();
        } catch (const std::exception& e) {
            DataBase->RollbackTransaction();
            throw MessageException(e.what(),"");
        }

        return GetSucceedMap(blSucceed);
    }

    bool MaterialProductCheck::insertMaterialProductStockRecord(const any &materialProductId, const any &storageId, float lostNum,bool isCancel) {
        string actionName = isCancel ? "取消库存盘点" : "库存盘点";
        auto parameters = make_shared<data_access::DataParameters>();
        parameters->Add("@MaterialProductId", materialProductId);
        parameters->Add("@StorageId", storageId);
        parameters->Add("@LostNum", lostNum);
        parameters->Add("@ActionName", actionName);
        parameters->Add("@CreateUser", Request->OperationUser);

        stringstream sql;
        sql << "insert into t_MaterialProduct_Stock_Record select uuid(),a.MaterialProductId,@StorageId,a.StockNum,";
        sql << (isCancel ? "@LostNum,":"0-@LostNum,");
        sql << (isCancel ? "a.StockNum+@LostNum," : "a.StockNum-@LostNum,");
        sql << "@ActionName,@CreateUser,CURRENT_TIMESTAMP,uuid() from t_materialproduct a";
        sql << " where a.MaterialProductId=@MaterialProductId";

        return DataBase->Execute(sql.str(), parameters)>0;
    }

    any MaterialProductCheck::CancelReview() {
        Actions::SetCancelReviewEntityData(shared_from_this());
        return UpdateStatus();
    }

    bool MaterialProductCheck::updateMaterialProductStockNum(const any &materialProductId, float lostNum) {
        auto parameters = make_shared<data_access::DataParameters>();
        parameters->Add("@MaterialProductId", materialProductId);
        parameters->Add("@LostNum", lostNum);

        string sql = "update t_MaterialProduct set StockNum=StockNum-@LostNum where MaterialProductId=@MaterialProductId";
        return DataBase->Execute(sql, parameters)>0;
    }

    any MaterialProductCheck::Insert2() {
        return Actions::Insert2(shared_from_this(), 8);
    }
}